/*******************************************************************************
** Qt Advanced Docking System
** Copyright (C) 2017 Uwe Kindler
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/


//============================================================================
/// \file   DockAreaWidget.cpp
/// \author Uwe Kindler
/// \date   24.02.2017
/// \brief  Implementation of CDockAreaWidget class
//============================================================================


//============================================================================
//                                   INCLUDES
//============================================================================
#include <AutoHideDockContainer.h>
#include <AutoHideTab.h>
#include "DockAreaWidget.h"

#include <QStackedLayout>
#include <QScrollBar>
#include <QWheelEvent>
#include <QStyle>
#include <QPushButton>
#include <QDebug>
#include <QMenu>
#include <QXmlStreamWriter>
#include <QList>

#include "ElidingLabel.h"
#include "DockContainerWidget.h"
#include "DockWidget.h"
#include "FloatingDockContainer.h"
#include "DockManager.h"
#include "DockOverlay.h"
#include "DockAreaTabBar.h"
#include "DockSplitter.h"
#include "DockAreaTitleBar.h"
#include "DockComponentsFactory.h"
#include "DockWidgetTab.h"
#include "DockingStateReader.h"


namespace ads
{
static const char* const INDEX_PROPERTY = "index";
static const char* const ACTION_PROPERTY = "action";

/**
 * 检查是否启用了自动隐藏功能
 */
static bool isAutoHideFeatureEnabled()
{
    return CDockManager::testAutoHideConfigFlag(CDockManager::AutoHideFeatureEnabled);
}

/**
 * 内部停靠区域布局模拟堆栈布局，但只将当前小部件插入到内部 QLayout 对象中。
 * \warning 只有当前小部件有父对象。所有其他小部件都没有父对象。
 * 这意味着，如果小部件不是当前小部件，则此布局中的小部件的 parent() 函数可能返回 nullptr。
 */
class CDockAreaLayout
{
private:
    QBoxLayout* m_ParentLayout;
    QList<QWidget*> m_Widgets;
    int m_CurrentIndex = -1;
    QWidget* m_CurrentWidget = nullptr;

public:
    /**
     * 使用给定的父布局创建实例
     */
    CDockAreaLayout(QBoxLayout* ParentLayout)
        : m_ParentLayout(ParentLayout)
    {
    }

    /**
     * 返回此布局中的小部件数
     */
    int count() const
    {
        return m_Widgets.count();
    }

    /**
     * 将小部件插入到内部小部件列表的给定索引位置
     */
    void insertWidget(int index, QWidget* Widget)
    {
        Widget->setParent(nullptr);
        if (index < 0)
        {
            index = m_Widgets.count();
        }
        m_Widgets.insert(index, Widget);
        if (m_CurrentIndex < 0)
        {
            setCurrentIndex(index);
        }
        else
        {
            if (index <= m_CurrentIndex )
            {
                ++m_CurrentIndex;
            }
        }
    }

    /**
     * 从布局中移除给定的小部件
     */
    void removeWidget(QWidget* Widget)
    {
        if (currentWidget() == Widget)
        {
            auto LayoutItem = m_ParentLayout->takeAt(1);
            if (LayoutItem)
            {
                LayoutItem->widget()->setParent(nullptr);
            }
            delete LayoutItem;
            m_CurrentWidget = nullptr;
            m_CurrentIndex = -1;
        }
        else if (indexOf(Widget) < m_CurrentIndex)
        {
            --m_CurrentIndex;
        }
        m_Widgets.removeOne(Widget);
    }

    /**
     * 返回当前选择的小部件
     */
    QWidget* currentWidget() const
    {
        return m_CurrentWidget;
    }

    /**
     * 激活具有给定索引的小部件
     */
    void setCurrentIndex(int index)
    {
        QWidget *prev = currentWidget();
        QWidget *next = widget(index);
        if (!next || (next == prev && !m_CurrentWidget))
        {
            return;
        }
        bool reenableUpdates = false;
        QWidget *parent = m_ParentLayout->parentWidget();
        if (parent && parent->updatesEnabled())
        {
            reenableUpdates = true;
            parent->setUpdatesEnabled(false);
        }
        auto LayoutItem = m_ParentLayout->takeAt(1);
        if (LayoutItem)
        {
            LayoutItem->widget()->setParent(nullptr);
        }
        delete LayoutItem;
        m_ParentLayout->addWidget(next);
        if (prev)
        {
            prev->hide();
        }
        m_CurrentIndex = index;
        m_CurrentWidget = next;
        if (reenableUpdates)
        {
            parent->setUpdatesEnabled(true);
        }
    }

    /**
     * 返回当前活动小部件的索引
     */
    int currentIndex() const
    {
        return m_CurrentIndex;
    }

    /**
     * 如果布局中没有小部件，则返回 true
     */
    bool isEmpty() const
    {
        return m_Widgets.empty();
    }

    /**
     * 返回给定小部件的索引
     */
    int indexOf(QWidget* w) const
    {
        return m_Widgets.indexOf(w);
    }

    /**
     * 返回给定索引的小部件
     */
    QWidget* widget(int index) const
    {
        return (index < m_Widgets.size()) ? m_Widgets.at(index) : nullptr;
    }

    /**
     * 返回当前活动小部件的几何形状
     */
    QRect geometry() const
    {
        return m_Widgets.empty() ? QRect() : currentWidget()->geometry();
    }
};

using DockAreaLayout = CDockAreaLayout;
static const DockWidgetAreas DefaultAllowedAreas = AllDockAreas;


/**
 * CDockAreaWidget类的私有数据类（pimpl）
 */
struct DockAreaWidgetPrivate
{
    CDockAreaWidget* _this = nullptr;
    QBoxLayout* Layout = nullptr;
    DockAreaLayout* ContentsLayout = nullptr;
    CDockAreaTitleBar* TitleBar = nullptr;
    CDockManager* DockManager = nullptr;
    CAutoHideDockContainer* AutoHideDockContainer = nullptr;
    bool UpdateTitleBarButtons = false;
    DockWidgetAreas AllowedAreas = DefaultAllowedAreas;
    QSize MinSizeHint;
    CDockAreaWidget::DockAreaFlags Flags{ CDockAreaWidget::DefaultFlags };

    /**
     * 私有数据构造函数
     */
    DockAreaWidgetPrivate(CDockAreaWidget* _public);

    /**
     * 创建带有选项卡和关闭按钮的顶部区域布局
     */
    void createTitleBar();

    /**
     * 返回给定索引处的停靠窗口
     */
    CDockWidget* dockWidgetAt(int index)
    {
        return qobject_cast<CDockWidget*>(ContentsLayout->widget(index));
    }

    /**
     * 通过索引方便地访问选项卡小部件
     */
    CDockWidgetTab* tabWidgetAt(int index)
    {
        return dockWidgetAt(index)->tabWidget();
    }

    /**
     * 返回给定停靠窗口的选项卡操作
     */
    QAction* dockWidgetTabAction(CDockWidget* DockWidget) const
    {
        return qvariant_cast<QAction*>(DockWidget->property(ACTION_PROPERTY));
    }

    /**
     * 返回给定停靠窗口的索引
     */
    int dockWidgetIndex(CDockWidget* DockWidget) const
    {
        return DockWidget->property(INDEX_PROPERTY).toInt();
    }

    /**
     * 用于访问选项卡栏的便利函数
     */
    CDockAreaTabBar* tabBar() const
    {
        return TitleBar->tabBar();
    }

    /**
     * 更新关闭和分离按钮的可用状态
     */
    void updateTitleBarButtonStates();

    /**
     * 更新关闭和分离按钮的可见性
     */
    void updateTitleBarButtonVisibility(bool isTopLevel);

    /**
     * 扫描所有包含的停靠窗口以获取最大的最小大小提示
     */
    void updateMinimumSizeHint()
    {
        MinSizeHint = QSize();
        for (int i = 0; i < ContentsLayout->count(); ++i)
        {
            auto Widget = ContentsLayout->widget(i);
            MinSizeHint.setHeight(qMax(MinSizeHint.height(), Widget->minimumSizeHint().height()));
            MinSizeHint.setWidth(qMax(MinSizeHint.width(), Widget->minimumSizeHint().width()));
        }
    }
};

//============================================================================

DockAreaWidgetPrivate::DockAreaWidgetPrivate(CDockAreaWidget* _public) :
    _this(_public)
{
}

//============================================================================

void DockAreaWidgetPrivate::createTitleBar()
{
    TitleBar = componentsFactory()->createDockAreaTitleBar(_this);
    Layout->addWidget(TitleBar);
    QObject::connect(tabBar(), &CDockAreaTabBar::tabCloseRequested, _this, &CDockAreaWidget::onTabCloseRequested);
    QObject::connect(TitleBar, &CDockAreaTitleBar::tabBarClicked, _this, &CDockAreaWidget::setCurrentIndex);
    QObject::connect(tabBar(), &CDockAreaTabBar::tabMoved, _this, &CDockAreaWidget::reorderDockWidget);
}

//============================================================================

void DockAreaWidgetPrivate::updateTitleBarButtonStates()
{
    if (_this->isHidden())
    {
        UpdateTitleBarButtons = true;
        return;
    }
    TitleBar->button(TitleBarButtonClose)->setEnabled(
        _this->features().testFlag(CDockWidget::DockWidgetClosable));
    TitleBar->button(TitleBarButtonUndock)->setEnabled(
        _this->features().testFlag(CDockWidget::DockWidgetFloatable));
    TitleBar->button(TitleBarButtonAutoHide)->setEnabled(
        _this->features().testFlag(CDockWidget::DockWidgetPinnable));
    TitleBar->updateDockWidgetActionsButtons();
    UpdateTitleBarButtons = false;
}

//============================================================================

void DockAreaWidgetPrivate::updateTitleBarButtonVisibility(bool IsTopLevel)
{
    auto* const container = _this->dockContainer();
    if (!container)
    {
        return;
    }
    if (IsTopLevel)
    {
        TitleBar->button(TitleBarButtonClose)->setVisible(!container->isFloating());
        TitleBar->button(TitleBarButtonAutoHide)->setVisible(!container->isFloating());
        // 自动隐藏时，不应显示分离和选项卡按钮
        TitleBar->button(TitleBarButtonUndock)->setVisible(!container->isFloating() && !_this->isAutoHide());
        TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide());
    }
    else
    {
        TitleBar->button(TitleBarButtonClose)->setVisible(true);
        TitleBar->button(TitleBarButtonAutoHide)->setVisible(true);
        TitleBar->button(TitleBarButtonUndock)->setVisible(!_this->isAutoHide());
        TitleBar->button(TitleBarButtonTabsMenu)->setVisible(!_this->isAutoHide());
    }
}

//============================================================================

CDockAreaWidget::CDockAreaWidget(CDockManager* DockManager, CDockContainerWidget* parent) :
    QFrame(parent),
    d(new DockAreaWidgetPrivate(this))
{
    d->DockManager = DockManager;
    d->Layout = new QBoxLayout(QBoxLayout::TopToBottom);
    d->Layout->setContentsMargins(0, 0, 0, 0);
    d->Layout->setSpacing(0);
    setLayout(d->Layout);
    d->createTitleBar();
    d->ContentsLayout = new DockAreaLayout(d->Layout);
    if (d->DockManager)
    {
        Q_EMIT d->DockManager->dockAreaCreated(this);
    }
}

//============================================================================

CDockAreaWidget::~CDockAreaWidget()
{
    ADS_PRINT("~CDockAreaWidget()");
    delete d->ContentsLayout;
    delete d;
}

//============================================================================

CDockManager* CDockAreaWidget::dockManager() const
{
    return d->DockManager;
}

//============================================================================

CDockContainerWidget* CDockAreaWidget::dockContainer() const
{
    return internal::findParent<CDockContainerWidget*>(this);
}

//============================================================================

CAutoHideDockContainer* CDockAreaWidget::autoHideDockContainer() const
{
    return d->AutoHideDockContainer;
}

//============================================================================

bool CDockAreaWidget::isAutoHide() const
{
    return d->AutoHideDockContainer != nullptr;
}

// 设置自动隐藏的 Dock 容器
void CDockAreaWidget::setAutoHideDockContainer(CAutoHideDockContainer* AutoHideDockContainer)
{
    d->AutoHideDockContainer = AutoHideDockContainer;
    updateAutoHideButtonCheckState(); // 更新自动隐藏按钮的状态
    updateTitleBarButtonsToolTips(); // 更新标题栏按钮的提示
    d->TitleBar->button(TitleBarButtonAutoHide)->setShowInTitleBar(true); // 在标题栏中显示自动隐藏按钮
}

// 添加 DockWidget
void CDockAreaWidget::addDockWidget(CDockWidget* DockWidget)
{
    insertDockWidget(d->ContentsLayout->count(), DockWidget); // 在末尾插入 DockWidget
}

// 插入 DockWidget
void CDockAreaWidget::insertDockWidget(int index, CDockWidget* DockWidget, bool Activate)
{
    // 如果 index 不合法，则将 index 设置为末尾
    if (index < 0 || index > d->ContentsLayout->count())
    {
        index = d->ContentsLayout->count();
    }
    // 在 ContentsLayout 中插入 DockWidget
    d->ContentsLayout->insertWidget(index, DockWidget);
    DockWidget->setDockArea(this); // 设置 DockWidget 的 DockArea
    DockWidget->tabWidget()->setDockAreaWidget(this); // 设置 DockWidget 的 TabWidget 的 DockAreaWidget
    auto TabWidget = DockWidget->tabWidget();
    // 插入 Tab 会改变当前索引，从而使 TabWidget 在槽中可见
    d->tabBar()->blockSignals(true); // 防止信号递归
    d->tabBar()->insertTab(index, TabWidget); // 在 TabBar 中插入 TabWidget
    d->tabBar()->blockSignals(false);
    TabWidget->setVisible(!DockWidget->isClosed()); // 设置 TabWidget 可见性
    d->TitleBar->autoHideTitleLabel()->setText(DockWidget->windowTitle()); // 设置自动隐藏标题标签的文本
    DockWidget->setProperty(INDEX_PROPERTY, index); // 设置 DockWidget 的属性
    // 更新最小大小提示
    d->MinSizeHint.setHeight(qMax(d->MinSizeHint.height(), DockWidget->minimumSizeHint().height()));
    d->MinSizeHint.setWidth(qMax(d->MinSizeHint.width(), DockWidget->minimumSizeHint().width()));
    if (Activate)
    {
        setCurrentIndex(index); // 设置当前索引
        DockWidget->setClosedState(false); // 设置 DockWidget 的关闭状态为 false，以保持关闭状态一致
    }
    // 如果 DockArea 隐藏，则需要调用 DockWidget->toggleViewInternal(true) 使其可见
    if (!this->isVisible() && d->ContentsLayout->count() > 1 && !dockManager()->isRestoringState())
    {
        DockWidget->toggleViewInternal(true);
    }
    d->updateTitleBarButtonStates(); // 更新标题栏按钮状态
    updateTitleBarVisibility(); // 更新标题栏可见性
}

// 移除 DockWidget
void CDockAreaWidget::removeDockWidget(CDockWidget* DockWidget)
{
    ADS_PRINT("CDockAreaWidget::removeDockWidget");
    if (!DockWidget)
    {
        return;
    }
    // 如果 DockArea 在自动隐藏容器中，则可以立即删除自动隐藏容器
    if (isAutoHide())
    {
        autoHideDockContainer()->cleanupAndDelete();
        return;
    }
    auto CurrentDockWidget = currentDockWidget();
    auto NextOpenDockWidget = (DockWidget == CurrentDockWidget) ? nextOpenDockWidget(DockWidget) : nullptr;
    d->ContentsLayout->removeWidget(DockWidget); // 从 ContentsLayout 中移除 DockWidget
    auto TabWidget = DockWidget->tabWidget();
    TabWidget->hide(); // 隐藏 TabWidget
    d->tabBar()->removeTab(TabWidget); // 从 TabBar 中移除 TabWidget
    TabWidget->setParent(DockWidget);
    DockWidget->setDockArea(nullptr); // 清除 DockWidget 的 DockArea
    CDockContainerWidget* DockContainer = dockContainer();
    if (NextOpenDockWidget)
    {
        setCurrentDockWidget(NextOpenDockWidget); // 设置当前 DockWidget
    }
    else if (d->ContentsLayout->isEmpty() && DockContainer->dockAreaCount() >= 1)
    {
        ADS_PRINT("Dock Area empty");
        DockContainer->removeDockArea(this); // 移除 DockArea
        this->deleteLater(); // 延迟删除 DockArea
        if (DockContainer->dockAreaCount() == 0)
        {
            if (CFloatingDockContainer* FloatingDockContainer = DockContainer->floatingWidget())
            {
                FloatingDockContainer->hide(); // 隐藏浮动窗口
                FloatingDockContainer->deleteLater(); // 延迟删除浮动窗口
            }
        }
    }
    else if (DockWidget == CurrentDockWidget)
    {
        // 如果 ContentsLayout 不为空但没有更多的打开 DockWidget，则需要隐藏 DockArea，因为它不包含任何可见内容
        hideAreaWithNoVisibleContent();
    }
    d->updateTitleBarButtonStates(); // 更新标题栏按钮状态
    updateTitleBarVisibility(); // 更新标题栏可见性
    d->updateMinimumSizeHint(); // 更新最小大小提示
    auto TopLevelDockWidget = DockContainer->topLevelDockWidget();
    if (TopLevelDockWidget)
    {
        TopLevelDockWidget->emitTopLevelChanged(true); // 发射 topLevelChanged 信号
    }
#if (ADS_DEBUG_LEVEL > 0)
    DockContainer->dumpLayout(); // 输出布局信息
#endif
}

// 隐藏不包含可见内容的 DockArea
void CDockAreaWidget::hideAreaWithNoVisibleContent()
{
    this->toggleView(false); // 隐藏 DockArea
    // 隐藏空父分隔器
    auto Splitter = internal::findParent<CDockSplitter*>(this);
    internal::hideEmptyParentSplitters(Splitter);
    // 隐藏空浮动窗口
    CDockContainerWidget* Container = this->dockContainer();
    if (!Container->isFloating() && !CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar))
    {
        return;
    }
    updateTitleBarVisibility(); // 更新标题栏可见性
    auto TopLevelWidget = Container->topLevelDockWidget();
    auto FloatingWidget = Container->floatingWidget();
    if (TopLevelWidget)
    {
        if (FloatingWidget)
        {
            FloatingWidget->updateWindowTitle(); // 更新浮动窗口标题
        }
        CDockWidget::emitTopLevelEventForWidget(TopLevelWidget, true); // 发射 topLevelChanged 信号
    }
    else if (Container->openedDockAreas().isEmpty() && FloatingWidget)
    {
        FloatingWidget->hide(); // 隐藏浮动窗口
    }
    if (isAutoHide())
    {
        autoHideDockContainer()->hide(); // 隐藏自动隐藏容器
    }
}

// Tab 关闭请求
void CDockAreaWidget::onTabCloseRequested(int Index)
{
    ADS_PRINT("CDockAreaWidget::onTabCloseRequested " << Index);
    dockWidget(Index)->requestCloseDockWidget(); // 请求关闭 DockWidget
}

// 获取当前 DockWidget
CDockWidget* CDockAreaWidget::currentDockWidget() const
{
    int CurrentIndex = currentIndex();
    if (CurrentIndex < 0)
    {
        return nullptr;
    }
    return dockWidget(CurrentIndex);
}

// 设置当前 DockWidget
void CDockAreaWidget::setCurrentDockWidget(CDockWidget* DockWidget)
{
    if (dockManager()->isRestoringState())
    {
        return;
    }
    internalSetCurrentDockWidget(DockWidget); // 内部设置当前 DockWidget
}


//============================================================================
void CDockAreaWidget::internalSetCurrentDockWidget(CDockWidget* DockWidget)
{
    // 获取DockWidget在ContentsLayout中的索引
    int Index = index(DockWidget);
    if (Index < 0)
    {
        return;
    }
    // 设置当前索引
    setCurrentIndex(Index);
    // 设置DockWidget的关闭状态为false，以保持关闭状态一致
    DockWidget->setClosedState(false);
}
//============================================================================
void CDockAreaWidget::setCurrentIndex(int index)
{
    auto TabBar = d->tabBar();
    if (index < 0 || index > (TabBar->count() - 1))
    {
        // 输出警告信息
        qWarning() << Q_FUNC_INFO << "Invalid index" << index;
        return;
    }
    auto cw = d->ContentsLayout->currentWidget();
    auto nw = d->ContentsLayout->widget(index);
    if (cw == nw && !nw->isHidden())
    {
        return;
    }
    // 发送currentChanging信号
    Q_EMIT currentChanging(index);
    // 设置TabBar的当前索引
    TabBar->setCurrentIndex(index);
    d->ContentsLayout->setCurrentIndex(index);
    // 显示当前Widget
    d->ContentsLayout->currentWidget()->show();
    // 发送currentChanged信号
    Q_EMIT currentChanged(index);
}
//============================================================================
int CDockAreaWidget::currentIndex() const
{
    return d->ContentsLayout->currentIndex();
}
//============================================================================
QRect CDockAreaWidget::titleBarGeometry() const
{
    return d->TitleBar->geometry();
}
//============================================================================
QRect CDockAreaWidget::contentAreaGeometry() const
{
    return d->ContentsLayout->geometry();
}
//============================================================================
int CDockAreaWidget::index(CDockWidget* DockWidget)
{
    return d->ContentsLayout->indexOf(DockWidget);
}
//============================================================================
QList<CDockWidget*> CDockAreaWidget::dockWidgets() const
{
    QList<CDockWidget*> DockWidgetList;
    for (int i = 0; i < d->ContentsLayout->count(); ++i)
    {
        DockWidgetList.append(dockWidget(i));
    }
    return DockWidgetList;
}
//============================================================================
int CDockAreaWidget::openDockWidgetsCount() const
{
    int Count = 0;
    for (int i = 0; i < d->ContentsLayout->count(); ++i)
    {
        if (!dockWidget(i)->isClosed())
        {
            ++Count;
        }
    }
    return Count;
}
//============================================================================
QList<CDockWidget*> CDockAreaWidget::openedDockWidgets() const
{
    QList<CDockWidget*> DockWidgetList;
    for (int i = 0; i < d->ContentsLayout->count(); ++i)
    {
        CDockWidget* DockWidget = dockWidget(i);
        if (!DockWidget->isClosed())
        {
            DockWidgetList.append(dockWidget(i));
        }
    }
    return DockWidgetList;
}
//============================================================================
int CDockAreaWidget::indexOfFirstOpenDockWidget() const
{
    for (int i = 0; i < d->ContentsLayout->count(); ++i)
    {
        if (!dockWidget(i)->isClosed())
        {
            return i;
        }
    }
    return -1;
}
//============================================================================
int CDockAreaWidget::dockWidgetsCount() const
{
    return d->ContentsLayout->count();
}
//============================================================================
CDockWidget* CDockAreaWidget::dockWidget(int Index) const
{
    return qobject_cast<CDockWidget*>(d->ContentsLayout->widget(Index));
}
//============================================================================
void CDockAreaWidget::reorderDockWidget(int fromIndex, int toIndex)
{
    ADS_PRINT("CDockAreaWidget::reorderDockWidget");
    if (fromIndex >= d->ContentsLayout->count() || fromIndex < 0
        || toIndex >= d->ContentsLayout->count() || toIndex < 0 || fromIndex == toIndex)
    {
        ADS_PRINT("Invalid index for tab movement" << fromIndex << toIndex);
        return;
    }
    auto Widget = d->ContentsLayout->widget(fromIndex);
    d->ContentsLayout->removeWidget(Widget);
    d->ContentsLayout->insertWidget(toIndex, Widget);
    setCurrentIndex(toIndex);
}
//============================================================================
void CDockAreaWidget::toggleDockWidgetView(CDockWidget* DockWidget, bool Open)
{
    Q_UNUSED(DockWidget);
    Q_UNUSED(Open);
    updateTitleBarVisibility();
}
//============================================================================
void CDockAreaWidget::updateTitleBarVisibility()
{
    CDockContainerWidget* Container = dockContainer();
    if (!Container)
    {
        return;
    }
    if (!d->TitleBar)
    {
        return;
    }
    bool IsAutoHide = isAutoHide();
    if (!CDockManager::testConfigFlag(CDockManager::AlwaysShowTabs))
    {
        bool Hidden = Container->hasTopLevelDockWidget() && (Container->isFloating()
            || CDockManager::testConfigFlag(CDockManager::HideSingleCentralWidgetTitleBar));
        Hidden |= (d->Flags.testFlag(HideSingleWidgetTitleBar) && openDockWidgetsCount() == 1);
        Hidden &= !IsAutoHide; // Titlebar must always be visible when auto hidden so it can be dragged
        d->TitleBar->setVisible(!Hidden);
    }
    if (isAutoHideFeatureEnabled())
    {
        auto tabBar = d->TitleBar->tabBar();
        tabBar->setVisible(!IsAutoHide);  // Never show tab bar when auto hidden
        d->TitleBar->autoHideTitleLabel()->setVisible(IsAutoHide);  // Always show when auto hidden, never otherwise
        updateTitleBarButtonVisibility(Container->topLevelDockArea() == this);
    }
}
//============================================================================
void CDockAreaWidget::markTitleBarMenuOutdated()
{
    if (d->TitleBar)
    {
        d->TitleBar->markTabsMenuOutdated();
    }
}
//============================================================================
void CDockAreaWidget::updateAutoHideButtonCheckState()
{
    auto autoHideButton = titleBarButton(TitleBarButtonAutoHide);
    autoHideButton->blockSignals(true);
    autoHideButton->setChecked(isAutoHide());
    autoHideButton->blockSignals(false);
}
//============================================================================
void CDockAreaWidget::updateTitleBarButtonVisibility(bool IsTopLevel) const
{
    d->updateTitleBarButtonVisibility(IsTopLevel);
}
//============================================================================
void CDockAreaWidget::updateTitleBarButtonsToolTips()
{
    internal::setToolTip(titleBarButton(TitleBarButtonClose),
        titleBar()->titleBarButtonToolTip(TitleBarButtonClose));
    internal::setToolTip(titleBarButton(TitleBarButtonAutoHide),
        titleBar()->titleBarButtonToolTip(TitleBarButtonAutoHide));
}


//============================================================================
void CDockAreaWidget::saveState(QXmlStreamWriter& s) const
{
    // 写入起始元素 "Area"
    s.writeStartElement("Area");

    // 写入属性 "Tabs"，值为 ContentsLayout 的数量
    s.writeAttribute("Tabs", QString::number(d->ContentsLayout->count()));

    // 获取当前的停靠窗口
    auto CurrentDockWidget = currentDockWidget();

    // 获取当前停靠窗口的对象名，如果为空则使用空字符串
    QString Name = CurrentDockWidget ? CurrentDockWidget->objectName() : "";

    // 写入属性 "Current"，值为当前停靠窗口的对象名
    s.writeAttribute("Current", Name);

    // 如果 AllowedAreas 属性与默认值不同，则写入属性 "AllowedAreas"
    if (d->AllowedAreas != DefaultAllowedAreas)
    {
        s.writeAttribute("AllowedAreas", QString::number(d->AllowedAreas, 16));
    }

    // 如果 Flags 属性与默认值不同，则写入属性 "Flags"
    if (d->Flags != DefaultFlags)
    {
        s.writeAttribute("Flags", QString::number(d->Flags, 16));
    }

    // 打印调试信息
    ADS_PRINT("CDockAreaWidget::saveState TabCount: " << d->ContentsLayout->count()
              << " Current: " << Name);

    // 保存 ContentsLayout 中每个停靠窗口的状态
    for (int i = 0; i < d->ContentsLayout->count(); ++i)
    {
        dockWidget(i)->saveState(s);
    }

    // 写入结束元素 "Area"
    s.writeEndElement();
}
//============================================================================
bool CDockAreaWidget::restoreState(CDockingStateReader& s, CDockAreaWidget*& CreatedWidget,
                                   bool Testing, CDockContainerWidget* Container)
{
    bool Ok;

    // 在测试中打印调试信息
#ifdef ADS_DEBUG_PRINT
    int Tabs = s.attributes().value("Tabs").toInt(&Ok);
    if (!Ok)
    {
        return false;
    }
#endif

    // 获取属性 "Current" 的值作为字符串
    QString CurrentDockWidget = s.attributes().value("Current").toString();

    // 打印调试信息
    ADS_PRINT("Restore NodeDockArea Tabs: " << Tabs << " Current: "
              << CurrentDockWidget);

    // 从容器中获取停靠管理器
    auto DockManager = Container->dockManager();

    // 如果不是在测试中，则创建一个新的停靠区域窗口
    CDockAreaWidget* DockArea = nullptr;
    if (!Testing)
    {
        DockArea = new CDockAreaWidget(DockManager, Container);

        // 如果属性 "AllowedAreas" 不为空，则设置允许的停靠区域
        const auto AllowedAreasAttribute = s.attributes().value("AllowedAreas");
        if (!AllowedAreasAttribute.isEmpty())
        {
            DockArea->setAllowedAreas((DockWidgetArea)AllowedAreasAttribute.toInt(nullptr, 16));
        }

        // 如果属性 "Flags" 不为空，则设置停靠区域的标志
        const auto FlagsAttribute = s.attributes().value("Flags");
        if (!FlagsAttribute.isEmpty())
        {
            DockArea->setDockAreaFlags((CDockAreaWidget::DockAreaFlags)FlagsAttribute.toInt(nullptr, 16));
        }
    }

    // 读取 XML 流中的每个起始元素
    while (s.readNextStartElement())
    {
        // 跳过非 "Widget" 的元素
        if (s.name() != QLatin1String("Widget"))
        {
            continue;
        }

        // 获取属性 "Name" 的值作为字符串
        auto ObjectName = s.attributes().value("Name");
        if (ObjectName.isEmpty())
        {
            return false;
        }

        // 获取属性 "Closed" 的值作为整数
        bool Closed = s.attributes().value("Closed").toInt(&Ok);
        if (!Ok)
        {
            return false;
        }

        // 跳过当前元素
        s.skipCurrentElement();

        // 在停靠管理器中查找具有指定对象名的停靠窗口
        CDockWidget* DockWidget = DockManager->findDockWidget(ObjectName.toString());
        if (!DockWidget || Testing)
        {
            continue;
        }

        // 打印调试信息
        ADS_PRINT("Dock Widget found - parent " << DockWidget->parent());

        // 清理并删除自动隐藏的停靠容器（如果存在）
        if (DockWidget->autoHideDockContainer())
        {
            DockWidget->autoHideDockContainer()->cleanupAndDelete();
        }

        // 隐藏停靠区域以防止在应用程序启动期间闪烁
        DockArea->hide();

        // 将停靠窗口添加到停靠区域
        DockArea->addDockWidget(DockWidget);

        // 根据 "Closed" 属性设置切换视图动作的选中状态
        DockWidget->setToggleViewActionChecked(!Closed);

        // 设置停靠窗口的关闭状态和属性
        DockWidget->setClosedState(Closed);
        DockWidget->setProperty(internal::ClosedProperty, Closed);
        DockWidget->setProperty(internal::DirtyProperty, false);
    }

    // 如果在测试中，则返回 true
    if (Testing)
    {
        return true;
    }

    // 如果停靠区域没有任何停靠窗口，则删除停靠区域，否则设置当前停靠窗口
    if (!DockArea->dockWidgetsCount())
    {
        delete DockArea;
        DockArea = nullptr;
    }
    else
    {
        DockArea->setProperty("currentDockWidget", CurrentDockWidget);
    }

    // 设置创建的窗口并返回 true
    CreatedWidget = DockArea;
    return true;
}
//============================================================================
CDockWidget* CDockAreaWidget::nextOpenDockWidget(CDockWidget* DockWidget) const
{
    // 获取已打开的停靠窗口列表
    auto OpenDockWidgets = openedDockWidgets();

    // 检查是否有多个已打开的停靠窗口，或者唯一已打开的停靠窗口不是指定的停靠窗口
    if (OpenDockWidgets.count() > 1 || (OpenDockWidgets.count() == 1 && OpenDockWidgets[0] != DockWidget))
    {
        // 检查最后一个已打开的停靠窗口是否是指定的停靠窗口
        if (OpenDockWidgets.last() == DockWidget)
        {
            // 获取具有选项卡的下一个停靠窗口，向列表中的前面搜索
            for (int i = OpenDockWidgets.count() - 2; i >= 0; --i)
            {
                auto dw = OpenDockWidgets[i];
                if (!dw->features().testFlag(CDockWidget::NoTab))
                {
                    return dw;
                }
            }

            // 返回没有选项卡的下一个停靠窗口
            return OpenDockWidgets[OpenDockWidgets.count() - 2];
        }
        else
        {
            // 获取指定停靠窗口在列表中的索引
            int IndexOfDockWidget = OpenDockWidgets.indexOf(DockWidget);

            // 获取具有选项卡的下一个停靠窗口，向列表中的后面搜索
            for (int i = IndexOfDockWidget + 1; i < OpenDockWidgets.count(); ++i)
            {
                auto dw = OpenDockWidgets[i];
                if (!dw->features().testFlag(CDockWidget::NoTab))
                {
                    return dw;
                }
            }

            // 获取具有选项卡的下一个停靠窗口，向列表中的前面搜索
            for (int i = IndexOfDockWidget - 1; i >= 0; --i)
            {
                auto dw = OpenDockWidgets[i];
                if (!dw->features().testFlag(CDockWidget::NoTab))
                {
                    return dw;
                }
            }

            // 返回没有选项卡的下一个停靠窗口
            return OpenDockWidgets[IndexOfDockWidget + 1];
        }
    }
    else
    {
        // 如果没有其他已打开的停靠窗口，则返回 nullptr
        return nullptr;
    }
}


//============================================================================
// 根据给定的模式返回停靠区的特性。
// 如果模式为BitwiseAnd，则对区域中所有停靠窗口的特性执行按位与操作。
// 否则，执行按位或操作。
CDockWidget::DockWidgetFeatures CDockAreaWidget::features(eBitwiseOperator Mode) const
{
    if (BitwiseAnd == Mode)
    {
        CDockWidget::DockWidgetFeatures Features(CDockWidget::AllDockWidgetFeatures);
        for (const auto DockWidget : dockWidgets())
        {
            Features &= DockWidget->features();
        }
        return Features;
    }
    else
    {
        CDockWidget::DockWidgetFeatures Features(CDockWidget::NoDockWidgetFeatures);
        for (const auto DockWidget : dockWidgets())
        {
            Features |= DockWidget->features();
        }
        return Features;
    }
}
//============================================================================

// 此函数切换停靠区的可见性，并发出指示视图打开或关闭的信号。
void CDockAreaWidget::toggleView(bool Open)
{
    setVisible(Open);
    Q_EMIT viewToggled(Open);
}
//============================================================================

// 此函数设置停靠区的可见性，并在必要时更新标题栏按钮。
void CDockAreaWidget::setVisible(bool Visible)
{
    Super::setVisible(Visible);
    if (d->UpdateTitleBarButtons)
    {
        d->updateTitleBarButtonStates();
    }
}
//============================================================================

// 此函数设置允许停靠的区域。
void CDockAreaWidget::setAllowedAreas(DockWidgetAreas areas)
{
    d->AllowedAreas = areas;
}
//============================================================================

// 此函数返回允许停靠的区域。
DockWidgetAreas CDockAreaWidget::allowedAreas() const
{
    return d->AllowedAreas;
}
//============================================================================

// 此函数返回停靠区的标志。
CDockAreaWidget::DockAreaFlags CDockAreaWidget::dockAreaFlags() const
{
    return d->Flags;
}
//============================================================================

// 此函数设置停靠区的标志。
void CDockAreaWidget::setDockAreaFlags(DockAreaFlags Flags)
{
    auto ChangedFlags = d->Flags ^ Flags;
    d->Flags = Flags;
    if (ChangedFlags.testFlag(HideSingleWidgetTitleBar))
    {
        updateTitleBarVisibility();
    }
}
//============================================================================

// 此函数设置特定的停靠区标志。
void CDockAreaWidget::setDockAreaFlag(eDockAreaFlag Flag, bool On)
{
    auto flags = dockAreaFlags();
    internal::setFlag(flags, Flag, On);
    setDockAreaFlags(flags);
}
//============================================================================

// 此函数返回指定的标题栏按钮。
QAbstractButton* CDockAreaWidget::titleBarButton(TitleBarButton which) const
{
    return d->TitleBar->button(which);
}
//============================================================================

// 此函数关闭停靠区。如果只有一个单独的停靠窗口，并且该窗口具有DeleteOnClose特性或CustomCloseHandling特性，则关闭或删除该窗口。
// 否则，关闭或隐藏区域中的所有停靠窗口。
void CDockAreaWidget::closeArea()
{
    auto OpenDockWidgets = openedDockWidgets();
    if (OpenDockWidgets.count() == 1 &&
        (OpenDockWidgets[0]->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) ||
         OpenDockWidgets[0]->features().testFlag(CDockWidget::CustomCloseHandling)) &&
        !isAutoHide())
    {
        OpenDockWidgets[0]->closeDockWidgetInternal();
    }
    else
    {
        for (auto DockWidget : openedDockWidgets())
        {
            if ((DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) &&
                 DockWidget->features().testFlag(CDockWidget::DockWidgetForceCloseWithArea)) ||
                DockWidget->features().testFlag(CDockWidget::CustomCloseHandling))
            {
                DockWidget->closeDockWidgetInternal();
            }
            else if (DockWidget->features().testFlag(CDockWidget::DockWidgetDeleteOnClose) && isAutoHide())
            {
                DockWidget->closeDockWidgetInternal();
            }
            else
            {
                DockWidget->toggleView(false);
            }
        }
    }
}

// 此枚举定义了不同的边框位置。
enum eBorderLocation
{
    BorderNone = 0,
    BorderLeft = 0x01,
    BorderRight = 0x02,
    BorderTop = 0x04,
    BorderBottom = 0x08,
    BorderVertical = BorderLeft | BorderRight,
    BorderHorizontal = BorderTop | BorderBottom,
    BorderTopLeft = BorderTop | BorderLeft,
    BorderTopRight = BorderTop | BorderRight,
    BorderBottomLeft = BorderBottom | BorderLeft,
    BorderBottomRight = BorderBottom | BorderRight,
    BorderVerticalBottom = BorderVertical | BorderBottom,
    BorderVerticalTop = BorderVertical | BorderTop,
    BorderHorizontalLeft = BorderHorizontal | BorderLeft,
    BorderHorizontalRight = BorderHorizontal | BorderRight,
    BorderAll = BorderVertical | BorderHorizontal
};


//============================================================================
// 计算侧边选项卡栏的位置
SideBarLocation CDockAreaWidget::calculateSideTabBarArea() const
{
	// 获取停靠容器和内容矩形
	auto Container = dockContainer();
	auto ContentRect = Container->contentRect();

	// 初始化变量
	int borders = BorderNone; // 包含与停靠区域接触的所有边界
	auto DockAreaTopLeft = mapTo(Container, rect().topLeft());
	auto DockAreaRect = rect();
	DockAreaRect.moveTo(DockAreaTopLeft);
	const qreal aspectRatio = DockAreaRect.width() / (qMax(1, DockAreaRect.height()) * 1.0);
	const qreal sizeRatio = (qreal)ContentRect.width() / DockAreaRect.width();
	static const int MinBorderDistance = 16;
	bool HorizontalOrientation = (aspectRatio > 1.0) && (sizeRatio < 3.0);

	// 测量边界距离 - 距离小于 16 像素表示接触到边界
	int BorderDistance[4];
	int Distance = qAbs(ContentRect.topLeft().y() - DockAreaRect.topLeft().y());
	BorderDistance[SideBarLocation::SideBarTop] = (Distance < MinBorderDistance) ? 0 : Distance;
	if (!BorderDistance[SideBarLocation::SideBarTop])
	{
		borders |= BorderTop;
	}
	Distance = qAbs(ContentRect.bottomRight().y() - DockAreaRect.bottomRight().y());
	BorderDistance[SideBarLocation::SideBarBottom] = (Distance < MinBorderDistance) ? 0 : Distance;
	if (!BorderDistance[SideBarLocation::SideBarBottom])
	{
		borders |= BorderBottom;
	}
	Distance = qAbs(ContentRect.topLeft().x() - DockAreaRect.topLeft().x());
	BorderDistance[SideBarLocation::SideBarLeft] = (Distance < MinBorderDistance) ? 0 : Distance;
	if (!BorderDistance[SideBarLocation::SideBarLeft])
	{
		borders |= BorderLeft;
	}
	Distance = qAbs(ContentRect.bottomRight().x() - DockAreaRect.bottomRight().x());
	BorderDistance[SideBarLocation::SideBarRight] = (Distance < MinBorderDistance) ? 0 : Distance;
	if (!BorderDistance[SideBarLocation::SideBarRight])
	{
		borders |= BorderRight;
	}

	// 根据边界确定侧边选项卡栏的位置
	auto SideTab = SideBarLocation::SideBarRight;
	switch (borders)
	{
		// 1. 接触到所有边界
		case BorderAll: SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarRight; break;
		// 2. 接触到 3 条边界
		case BorderVerticalBottom : SideTab = SideBarLocation::SideBarBottom; break;
		case BorderVerticalTop : SideTab = SideBarLocation::SideBarTop; break;
		case BorderHorizontalLeft: SideTab = SideBarLocation::SideBarLeft; break;
		case BorderHorizontalRight: SideTab = SideBarLocation::SideBarRight; break;
		// 3. 接触到水平或垂直边界
		case BorderVertical : SideTab = SideBarLocation::SideBarBottom; break;
		case BorderHorizontal: SideTab = SideBarLocation::SideBarRight; break;
		// 4. 位于角落
		case BorderTopLeft : SideTab = HorizontalOrientation ? SideBarLocation::SideBarTop : SideBarLocation::SideBarLeft; break;
		case BorderTopRight : SideTab = HorizontalOrientation ? SideBarLocation::SideBarTop : SideBarLocation::SideBarRight; break;
		case BorderBottomLeft : SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarLeft; break;
		case BorderBottomRight : SideTab = HorizontalOrientation ? SideBarLocation::SideBarBottom : SideBarLocation::SideBarRight; break;
		// 5. 仅接触到一个边界
		case BorderLeft: SideTab = SideBarLocation::SideBarLeft; break;
		case BorderRight: SideTab = SideBarLocation::SideBarRight; break;
		case BorderTop: SideTab = SideBarLocation::SideBarTop; break;
		case BorderBottom: SideTab = SideBarLocation::SideBarBottom; break;
	}

	return SideTab;
}
//============================================================================

// 设置停靠区域小部件的自动隐藏功能
void CDockAreaWidget::setAutoHide(bool Enable, SideBarLocation Location, int TabIndex)
{
	// 检查自动隐藏功能是否已启用
	if (!isAutoHideFeatureEnabled())
	{
		return;
	}

	// 禁用自动隐藏功能
	if (!Enable)
	{
		if (isAutoHide())
		{
			d->AutoHideDockContainer->moveContentsToParent();
		}
		return;
	}

	// 如果已经是自动隐藏容器，则将其移动到新位置
	if (isAutoHide())
	{
		d->AutoHideDockContainer->moveToNewSideBarLocation(Location, TabIndex);
		return;
	}

	// 计算侧边选项卡栏的位置
	auto area = (SideBarNone == Location) ? calculateSideTabBarArea() : Location;

	// 为停靠小部件创建和设置自动隐藏容器
	for (const auto DockWidget : openedDockWidgets())
	{
		if (Enable == isAutoHide())
		{
			continue;
		}
		if (!DockWidget->features().testFlag(CDockWidget::DockWidgetPinnable))
		{
			continue;
		}
		dockContainer()->createAndSetupAutoHideContainer(area, DockWidget, TabIndex++);
	}
}
//============================================================================

// 切换停靠区域小部件的自动隐藏功能
void CDockAreaWidget::toggleAutoHide(SideBarLocation Location)
{
	// 检查自动隐藏功能是否已启用
	if (!isAutoHideFeatureEnabled())
	{
		return;
	}

	// 切换自动隐藏功能
	setAutoHide(!isAutoHide(), Location);
}
//============================================================================

// 关闭其他停靠区域
void CDockAreaWidget::closeOtherAreas()
{
	dockContainer()->closeOtherAreas(this);
}
//============================================================================

// 获取停靠区域小部件的标题栏
CDockAreaTitleBar* CDockAreaWidget::titleBar() const
{
	return d->TitleBar;
}
//============================================================================

// 检查停靠区域小部件是否为中央小部件区域
bool CDockAreaWidget::isCentralWidgetArea() const
{
	// 检查停靠区域小部件是否只有一个停靠小部件，并且该小部件是中央小部件
	if (dockWidgetsCount()!= 1)
	{
		return false;
	}
	return dockManager()->centralWidget() == dockWidgets().constFirst();
}
//============================================================================

// 检查停靠区域小部件是否包含中央小部件
bool CDockAreaWidget::containsCentralWidget() const
{
	auto centralWidget = dockManager()->centralWidget();
	for (const auto &dockWidget : dockWidgets())
	{
		if (dockWidget == centralWidget)
		{
			return true;
		}
	}
	return false;
}
//============================================================================

// 获取停靠区域小部件的最小大小提示
QSize CDockAreaWidget::minimumSizeHint() const
{
	// 检查最小大小提示是否有效
	if (!d->MinSizeHint.isValid())
	{
		return Super::minimumSizeHint();
	}

	// 计算最小大小提示
	if (d->TitleBar->isVisible())
	{
		return d->MinSizeHint + QSize(0, d->TitleBar->minimumSizeHint().height());
	}
	else
	{
		return d->MinSizeHint;
	}
}
//============================================================================

// 处理停靠小部件功能更改事件
void CDockAreaWidget::onDockWidgetFeaturesChanged()
{
	if (d->TitleBar)
	{
		d->updateTitleBarButtonStates();
	}
}
//============================================================================

// 检查停靠区域小部件是否为顶级区域
bool CDockAreaWidget::isTopLevelArea() const
{
	auto Container = dockContainer();
	if (!Container)
	{
		return false;
	}
	return (Container->topLevelDockArea() == this);
}
//============================================================================

// 将停靠区域小部件设置为浮动模式
void CDockAreaWidget::setFloating()
{
	d->TitleBar->setAreaFloating();
}

#ifdef Q_OS_WIN
//============================================================================

// 在 Windows 上处理停靠区域小部件的事件
bool CDockAreaWidget::event(QEvent *e)
{
	switch (e->type())
	{
	case QEvent::PlatformSurface: return true;
	default:
		break;
	}
	return Super::event(e);
}
#endif

} // namespace ads

//---------------------------------------------------------------------------
// EOF DockAreaWidget.cpp
